/**
 * Copyright 2010 The Regents of the University of California
 *
 *  All Rights Reserved
 */
/**
 *
 * File: fault-manager.h
 *
 */

#ifndef __FAULT_MANAGER_H__
#define __FAULT_MANAGER_H__

// public include files
#include <inttypes.h>
#include <openflow/openflow.h>

// forward declarations
struct ofpbuf;
struct DCSwitch_OFP_Edge_Fault;
struct lswitch;
struct rconn;
struct DCSwitch_OFP_Fault;
struct DCSwitch_OFP_HeartBeat;
// public constants

#define FaultManager_Switch_UP 1
#define FaultManager_Switch_DOWN 0

// public functions
void initializeFaultManager(void);

/**
 * returns the edge state for an edge
 */
enum EdgeState FaultManager_getEdgeState(uint32_t src_sw_index, uint32_t tar_sw_index);

/**
 * assigns the edge state for a particular edge.  A new edge will be created if it doesn't already exist
 */
void FaultManager_setEdgeState(uint32_t src_sw_index, uint32_t tar_sw_index, enum EdgeState edgeState);

/**
 * sets the node's status (invoked when handling heart-beat messages)
 */
void 
FaultManager_setNodeStatus(uint32_t src_sw_index, int status); 

/**
 * disables a particular switch and disables links to all of its neighbors
 * and broadcasts update back to remaining connected switches
 */
void FaultManager_disableSwitch(uint32_t src_sw_index);

/**
 * retrieves the node's status 
 */
int 
FaultManager_getNodeStatus(uint32_t src_sw_index);

/**
 * retrieves the last modify time for the src_sw_index
 */
time_t
FaultManager_getNodeLastModifyTime(uint32_t src_sw_index);

/**
 * assigns the edge state for a particular edge and also notifies consumers of this event that
 * a graph update has occurred.
 * @param sw - original switch that originated the fault 
 */
// void FaultManager_setEdgeStateAndNotify(struct lswitch *sw, uint32_t src_sw_index, uint32_t tar_sw_index, enum EdgeState edgeState);
void FaultManager_setEdgeStateAndNotify(uint32_t xid, uint32_t src_sw_index, uint32_t tar_sw_index, enum EdgeState edgeState);

/**
 * Creates a empty OFP_Fault Msg
 */
// struct ofpbuf* create_OFP_Fault_Msg(void);
struct ofpbuf* create_OFP_Fault_Msg(bool isNotify, int numEdgeFaults, struct DCSwitch_OFP_Edge_Fault *faults);

struct ofpbuf*
create_OFP_Fault_Msg_Xid(bool isNotify, int numEdgeFaults,
                         struct DCSwitch_OFP_Edge_Fault *faults, uint32_t xid); 
/**
 * handles the receipt of a Vendor specific DCSwitch OFP Fault message (secchan->controller)
 */
void handleDCSwitchFaultMsg(struct lswitch *sw, struct rconn *rc, struct DCSwitch_OFP_Fault *faultMsg);

/**
 * handles the receival of a heartbeat message from the switch/secchan
 */
void
handleDCSwitchHeartBeatMsg(struct lswitch *sw,
                           struct rconn *rc,
                           struct DCSwitch_OFP_HeartBeat* heartBeatMsg);

/**
 * creates a OFP_Heartbeat msg that will be sent from the switch->fabric manager/controller
 * @param switch_index The originating switch for the heart message
 * @returns an allocated ofpbuf pointer
 */
struct ofpbuf* create_OFP_Heartbeat_Msg(uint32_t switch_index);

/**
 * debug function that dumps the fault graph to stdout
 */ 
void
FaultManager_dumpFaultGraph(void);

/**
 * transmit the current graph state to the specified switch
 */
void 
FaultManager_updateSwitch(int switchIndex, int status);

bool isNewSwitch(struct lswitch *sw);
void updateDCSwitch(struct lswitch *sw, void *opp_);
bool isFault(void *opp_);
void insertPortDetails(struct lswitch *sw, void *opp_);
void printPortMap(int index);
void compute_shortest_path(int index);
bool isConnected(int swIndex1, int swIndex2);
int get_next_hop(int dst_index);
void processSwitchResponse(struct lswitch *sw, struct rconn *rconn, const struct ofp_flow_stats *fs);
uint16_t  determine_output_port(int index, int pod, int position, int port);

#endif
